package com.arcaneshift.servlet.action.game;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.arcaneshift.manager.action.game.DeckManager;
import com.arcaneshift.manager.action.user.UserManager;
import com.arcaneshift.manager.interfaces.IUserManager;
import com.arcaneshift.model.action.game.Deck;
import com.arcaneshift.model.request.AddDeckRequest;
import com.arcaneshift.model.response.AddDeckResponse;
import com.arcaneshift.model.validators.AddDeckValidator;
import com.arcaneshift.model.validators.system.SessionValidator;
import com.arcaneshift.security.errors.CardError;
import com.arcaneshift.security.errors.DeckError;
import com.arcaneshift.security.errors.UserError;
import com.arcaneshift.security.exceptions.CardException;
import com.arcaneshift.security.exceptions.DeckException;
import com.arcaneshift.servlet.util.network.RequestAction;
import com.arcaneshift.servlet.util.parser.AddDeckXMLParser;
import com.arcaneshift.util.SessionCacheContainer;
import com.common.model.abstracts.AbstractRequest;
import com.common.model.abstracts.AbstractValidator;
import com.common.model.validators.ActionValidator;
import com.common.security.abstracts.AbstractError;
import com.common.security.abstracts.AbstractException;
import com.common.security.abstracts.AbstractRuntimeException;
import com.common.security.errors.ParserError;
import com.common.security.exceptions.ManagerException;
import com.common.security.exceptions.ParserException;
import com.common.servlet.abstracts.AbstractParserServlet;
import com.common.servlet.interfaces.IParser;

public class AddDeckServlet extends AbstractParserServlet {
	private static final long serialVersionUID = 1L;
	private static Set<AbstractValidator> validators = new HashSet<AbstractValidator>();
	
	private AddDeckRequest requestContent;
	private AddDeckXMLParser parser = new AddDeckXMLParser();
	private DeckManager deckManager = new DeckManager();
	
	static {
		validators.add(new ActionValidator(RequestAction.ADD_DECK));
		validators.add(new SessionValidator());
		validators.add(new AddDeckValidator());
	}
	
	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response) {
		try {
			AddDeckResponse addDeckResponse = new AddDeckResponse();
			Deck deck = new Deck();
			deck.setName(requestContent.getName());
			deck.setCards(requestContent.getCards());
			
			if (requestContent.getUserId() == null) {
				Long playerId = SessionCacheContainer.getUserId(requestContent.getSessionId());
				deck.setPlayerId(playerId);
			} else {
				if (!userIdExists(requestContent.getUserId())) {
					error(new UserError(UserError.USER_NOT_FOUND), response);
					return;
				}
				deck.setPlayerId(requestContent.getUserId());
			}
			
			deckManager.save(deck);
			addDeckResponse.setRequestAction(requestContent.getAction());
			
			response.setContentType("text/xml");
			response.getWriter().write(parser().parseResponse(addDeckResponse));
			response.getWriter().close();
		} catch (ManagerException managerException) {
			exception(managerException, response);
		} catch (ParserException parserException) {
			exception(parserException, response);
		} catch (IOException ioException) {
			error(new ParserError(ParserError.STREAM_ERROR), response);
		} catch (DeckException deckException) {
			exception(deckException, response);
		}
	}

	@Override
	public void setRequest(AbstractRequest abstractRequest) {
		requestContent = (AddDeckRequest) abstractRequest;
	}

	@Override
	public Set<AbstractValidator> getValidators() {
		return validators;
	}

	@Override
	public IParser parser() {
		return parser;
	}
	
	@Override
	public void exception(AbstractException exception, HttpServletResponse response) {
		switch (exception.getCode()) {
			case ManagerException.DATABASE_EXCEPTION: {
				error(new UserError(AbstractError.DATABASE_ERROR), response);
				break;
			}
			case ParserException.CONVERSION_EXCEPTION: {
				error(new ParserError(ParserError.VALUE_CONVERT_ERROR), response);
				break;
			}
			default: {
				super.exception(exception, response);
			}
		}
	}
	
	public void exception(AbstractRuntimeException exception, HttpServletResponse response) {
		switch (exception.getCode()) {
			case CardException.CARD_TYPE_NOT_SUPPORTED: {
				error(new CardError(CardError.CARD_TYPE_NOT_SUPPORTED), response);
				break;
			}
			case DeckException.DECK_NOT_FOUND: {
				error(new DeckError(DeckError.DECK_NOT_FOUND), response);
				break;
			}
			case DeckException.MULTIPLE_DECKS_FOUND: {
				error(new DeckError(DeckError.MULTIPLE_DECKS_FOUND), response);
				break;
			}
			case DeckException.DECK_EXISTS: {
				error(new DeckError(DeckError.DECK_EXISTS), response);
				break;
			}
			default: {
				super.exception(exception, response);
				break;
			}
		}
	}
	
	private boolean userIdExists(Long userId) throws ManagerException {
		IUserManager userManager = new UserManager();
		return userManager.exist(userId);
	}
}